#!/usr/bin/python
"""
Testing framework for Kitsch

Runs all tests in the  /tests/ directory
Each test should be a 'test*.in' file with a corresponding 'test*.out'
"""

import os,subprocess,cStringIO

source_ext = ".k"
in_ext = ".in"
out_ext = ".out"
compiled_ext = ".ko"
cerror_ext = ".err"
interpreter_dir = "../bin"
interpreter_name = "Evaluator"
compiler_dir = "../bin"
compiler_name = "Compiler"
vm_dir = "../src"
vm_name = "vm.py"


"""
Runs a test with source file and compiler + virtual machine, returns whether or not the test was successful
"""
def runTestCompiler(testname,hasinput=False,haserrors=False):
    print "Running test: %s with compiler and VM..." % testname,
    
    try:
        if hasinput:
            fin = open(testname+in_ext,"r")
            program_input = fin.read()
        if haserrors:
            ferrors = open(testname+cerror_ext)
            expected_result = ferrors.read()
        else:
            fout = open(testname+out_ext,"r")
            expected_result = fout.read()
    except Exception,e:
        print "Error opening test files."
        print e
    
    output = ''
    # Compile the source file
    pstdout = os.popen('java -classpath %s %s %s %s 2>&1' % (compiler_dir,compiler_name,testname+source_ext,testname+compiled_ext))
    output += pstdout.read()
    if not haserrors:
        pstdin,pstdout = os.popen2('python %s %s 2>&1' % (os.path.join(vm_dir,vm_name),testname+compiled_ext))
        if hasinput:
            pstdin.write(program_input)
            pstdin.close()
    output += pstdout.read()
    
    if expected_result == output:
        print "PASS"
    else:
        print "FAIL"
        print "Expected output:"
        print "-"*80
        print expected_result
        print "-"*80
        print "Actual output:"
        print "-"*80
        print output
        print "-"*80

"""
Runs a test with a source file and interpreter, returns whether or not the test was successful
"""
def runTestInterpreter(testname,hasinput=False):
    print "Running test: %s with interpreter..." % testname,
    
    try:
        if hasinput:
            fin = open(testname+in_ext,"r")
            program_input = fin.read()
        fout = open(testname+out_ext,"r")
        expected_result = fout.read()
    except Exception,e:
        print "Error opening test files."
        print e
    
    pstdin,pstdout = os.popen2('java -classpath %s %s %s 2>&1' % (interpreter_dir,interpreter_name,testname+source_ext))
    if hasinput:
        pstdin.write(program_input)
        pstdin.close()
        
    output= ''
    output = pstdout.read()
    
    if expected_result == output:
        print "PASS"
    else:
        print "FAIL"
        print "Expected output:"
        print "-"*80
        print expected_result
        print "-"*80
        print "Actual output:"
        print "-"*80
        print output
        print "-"*80
    
    
def main():
    directories = ['.']
    while directories:
        dir = directories.pop()
        directories += [os.path.join(dir,d) for d in os.listdir(dir) if os.path.isdir(d) and not d.startswith(".")]
        for file in [os.path.join(dir,f.replace(source_ext,"")) for f in os.listdir(dir) if os.path.isfile(os.path.join(dir,f)) if f.startswith("test") and f.endswith(source_ext)]:
            if os.path.exists(file+out_ext):
                if os.path.exists(file+in_ext):
                    hasinput = True
                else:
                    hasinput = False
                    
                if os.path.exists(file+cerror_ext):
                    errors = True
                else:
                    errors = False
                    
                runTestInterpreter(file,hasinput=hasinput)
                runTestCompiler(file,hasinput=hasinput,haserrors=errors)
if __name__ == '__main__':
    main()
